package com.probiz.estore.aop;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import com.probiz.estore.common.model.system.VerFunc;
import com.probiz.estore.core.util.ContextUtil;
import com.probiz.estore.imports.web.action.CustomerImportController;
import com.probiz.estore.imports.web.action.ProductCategoryImportController;
import com.probiz.estore.imports.web.action.ProductImportController;
import com.probiz.estore.system.service.VerFuncManager;
import com.probiz.estoresa.catalog.web.action.VirtualCategoryController;
import com.probiz.estoresa.content.web.action.ContentSelectorController;
import com.probiz.estoresa.content.web.action.NewsletterController;
import com.probiz.estoresa.content.web.action.NewsletterGroupController;
import com.probiz.estoresa.content.web.action.SubscriberController;
import com.probiz.estoresa.customer.web.action.ConsultController;
import com.probiz.estoresa.customer.web.action.CustomerAttributeController;
import com.probiz.estoresa.customer.web.action.MembershipController;
import com.probiz.estoresa.customer.web.action.ProductReviewController;
import com.probiz.estoresa.other.web.action.TagController;
import com.probiz.estoresa.other.web.action.TagSelectorController;
import com.probiz.estoresa.product.web.action.SkuOptionController;
import com.probiz.estoresa.product.web.action.SkuOptionValueController;
import com.probiz.estoresa.product.web.action.StockNotifyController;
import com.probiz.estoresa.report.web.action.ReportDataController;
import com.probiz.estoresa.sales.web.action.GiftCertificateController;
import com.probiz.estoresa.sales.web.action.PromoRuleController;
import com.probiz.estoresa.system.web.action.AppAuditController;
import com.probiz.estoresa.system.web.action.SelfCollectionCentreController;
import com.probiz.estoresa.system.web.action.TaxController;
import com.probiz.estoresa.system.web.action.TaxRateController;
import com.probiz.estoresa.system.web.action.WrapController;

/**
 * 版本功能拦截器
 * 
 * 原理:该拦截器分两类拦截
 * 一类是controller上的拦截，spring-mvc.xml配置XML AOP。 另外一类是方法级别的拦截，调用VerFuncInterceptor.getInstance().invoke(),在页面上使用verFunc:verFuncValidate Tag进行界面元素的屏蔽
 * 
 * 
 */
public class VerFuncInterceptor implements HandlerInterceptor,InitializingBean {
	private static final Log logger = LogFactory.getLog(VerFuncInterceptor.class);

	private static VerFuncInterceptor verFuncInterceptor = new VerFuncInterceptor();

	private VerFuncInterceptor() {
		super();
	}

	public static VerFuncInterceptor getInstance() {
		return verFuncInterceptor;
	}

	/**
	 * 保存funcKey和funcValue对 例如: multiSku:true, gift:false等
	 */
	private Map<String, Boolean> funcMap = new HashMap<String, Boolean>();
	/**
	 * 保存controller和funcKey对 例如：com.probiz.estoresa.product.web.action.StockNotifyController:multiSku等
	 */
	private Map<String, String> controllerClassMap = new HashMap<String, String>();
	
	private Map<String, String> funcNameMap = new HashMap<String, String>();

	private VerFuncManager verFuncManager;

	public void setVerFuncManager(VerFuncManager verFuncManager) {
		this.verFuncManager = verFuncManager;
	}
	
	public void afterPropertiesSet() throws Exception {
	}

	/**
	 * 初始化 funcMap
	 */
	public void init() {
		//初始化funcMap 数据库存储的funcKey形如: multiSku,funcValue形如：multiSku_on 两者都是base64的加密值
		List<VerFunc> verFuncList = verFuncManager.listAll();
		for (VerFunc verFunc : verFuncList) {
			String funcKeyEncode = verFunc.getFuncKey();
			String funcKeyDecode = new String(Base64.decodeBase64(funcKeyEncode.getBytes()));
			String funcValueEncode = verFunc.getFuncValue();
			String funcValueDecode = new String(Base64.decodeBase64(funcValueEncode.getBytes()));
			try{
				String[] values = funcValueDecode.split(Constants.SPLITER);
				String onOrOff = values[1];
				if (Constants.ON.equals(onOrOff)) {
					funcMap.put(funcKeyDecode, Boolean.TRUE);
				} else if (Constants.OFF.endsWith(onOrOff)) {
					funcMap.put(funcKeyDecode, Boolean.FALSE);
				}
			}catch(Exception e){
				logger.error("version function interceptor wrong funcValue for funcKey:"+funcKeyDecode);
			}
		}
		//对controller的拦截必须分:开前com.probiz.estoresf.*,后台com.probiz.estoresa.*
		
		if(ContextUtil.getInstance().isStoreAdmin()){
			//商品管理(多规格、关联规格、规格管理)
			controllerClassMap.put(SkuOptionController.class.getName(), Constants.multiSku);
			controllerClassMap.put(SkuOptionValueController.class.getName(), Constants.multiSku);			
			//缺货登记(缺货登记管理)
			controllerClassMap.put(StockNotifyController.class.getName(), Constants.stockNotify);
			//专场目录(专场活动添加、修改、删除、设置过滤条件和手动添加商品)
			controllerClassMap.put(VirtualCategoryController.class.getName(), Constants.virtualCategory);
			//文章管理(文章关联推荐)
			controllerClassMap.put(ContentSelectorController.class.getName(), Constants.contentRelated4Content);
			//内容目录管理(内容目录关联推荐)
			controllerClassMap.put(ContentSelectorController.class.getName(), Constants.contentRelated4Category);
			//促销活动(购物车、目录、优惠券促销)
			controllerClassMap.put(PromoRuleController.class.getName(), Constants.promoRule);
			//礼券管理(礼券添加，禁用，发送礼券邮件)
			controllerClassMap.put(GiftCertificateController.class.getName(), Constants.giftCertificate);
			//商品评论管理(查看客户评论/商品评论显示、隐藏、置顶、取消置顶、标识为已阅、标识为未阅、删除/管理员回复、查看回复)
			controllerClassMap.put(ProductReviewController.class.getName(), Constants.productReview);
			//商品咨询管理(查看客户咨询/商品咨询显示、隐藏、标识为已阅、标识为未阅、删除/管理员回复、查看回复)
			controllerClassMap.put(ConsultController.class.getName(), Constants.productConsult);
			//添加、修改、删除自定义客户注册项
			controllerClassMap.put(CustomerAttributeController.class.getName(), Constants.customerAttr);
			//会员等级管理(添加修改删除客户等级、会员自动升级)
			controllerClassMap.put(MembershipController.class.getName(), Constants.membership);
			//信息订阅(添加、修改、删除订阅信息分类/添加、修改、删除订阅信息/查看、删除订阅邮件)
			controllerClassMap.put(NewsletterGroupController.class.getName(), Constants.subscriber);
			controllerClassMap.put(NewsletterController.class.getName(), Constants.subscriber);
			controllerClassMap.put(SubscriberController.class.getName(), Constants.subscriber);
			//物流与配送(添加、修改、删除提货中心)
			controllerClassMap.put(SelfCollectionCentreController.class.getName(), Constants.selfCollection);
			//包装管理(添加、修改、删除包装)
			controllerClassMap.put(WrapController.class.getName(), Constants.wrap);
			//税管理(添加、修改、删除税和税率)
			controllerClassMap.put(TaxController.class.getName(), Constants.tax);
			controllerClassMap.put(TaxRateController.class.getName(), Constants.tax);
			//安全日志(查看、删除安全日志)
			controllerClassMap.put(AppAuditController.class.getName(), Constants.appAudit);
			//导入(商品、商品目录、客户批量导入)
			controllerClassMap.put(CustomerImportController.class.getName(), Constants.importTool);
			controllerClassMap.put(ProductImportController.class.getName(), Constants.importTool);
			controllerClassMap.put(ProductCategoryImportController.class.getName(), Constants.importTool);
			//标签管理(对商品、文章、订单、会员加入自定义标签)
			controllerClassMap.put(TagController.class.getName(), Constants.tag);
			controllerClassMap.put(TagSelectorController.class.getName(), Constants.tag);
			//报表统计(销售额统计、订单交易量趋势、商品销售排行、会员购买排行、销售指标分析、会员注册量趋势)
			controllerClassMap.put(ReportDataController.class.getName(), Constants.report);
			
		}else if(ContextUtil.getInstance().isStoreFront()){
			//专场目录
			controllerClassMap.put(com.probiz.estoresf.catalog.web.action.VirtualCategoryFrontController.class.getName(), Constants.virtualCategory);
			//商品对比，对比栏
			controllerClassMap.put(com.probiz.estoresf.product.web.action.CompareCartFrontController.class.getName(), Constants.compareCart);
			//礼券管理(礼券添加，禁用，发送礼券邮件)
			controllerClassMap.put(com.probiz.estoresf.sales.web.action.GiftCertificateFrontController.class.getName(), Constants.giftCertificate);
			//促销活动(购物车、目录、优惠券促销)
			controllerClassMap.put(com.probiz.estoresf.sales.web.action.PromoRuleListFrontController.class.getName(), Constants.promoRule);
			controllerClassMap.put(com.probiz.estoresf.sales.web.action.PromoRuleFrontController.class.getName(), Constants.promoRule);
			
			//controllerClassMap.put(com.probiz.estoresf.customer.web.action.GiftCouponFrontController.class.getName(), Constants.coupon);
			
			//商品评论管理(查看客户评论/商品评论显示、隐藏、置顶、取消置顶、标识为已阅、标识为未阅、删除/管理员回复、查看回复)
			controllerClassMap.put(com.probiz.estoresf.customer.web.action.ProductReviewFrontController.class.getName(), Constants.productReview);
			controllerClassMap.put(com.probiz.estoresf.customer.web.action.CsProductReviewFrontController.class.getName(), Constants.productReview);
			//商品咨询管理(查看客户咨询/商品咨询显示、隐藏、标识为已阅、标识为未阅、删除/管理员回复、查看回复)
			controllerClassMap.put(com.probiz.estoresf.customer.web.action.ConsultFrontController.class.getName(), Constants.productConsult);
			controllerClassMap.put(com.probiz.estoresf.customer.web.action.CsConsultFrontController.class.getName(), Constants.productConsult);
			//信息订阅(添加、修改、删除订阅信息分类/添加、修改、删除订阅信息/查看、删除订阅邮件)
			controllerClassMap.put(com.probiz.estoresf.customer.web.action.NewsSubscriptionController.class.getName(), Constants.subscriber);
			//会员等级与积分：查看等级权利与升级条件，查看积分消费与获得历史
			controllerClassMap.put(com.probiz.estoresf.customer.web.action.CsShopPointFrontController.class.getName(), Constants.shopPoint);
			//缺货登记(缺货登记管理)
			controllerClassMap.put(com.probiz.estoresf.customer.web.action.CsStockNotifyFrontController.class.getName(), Constants.stockNotify);
		}
	}

	/**
	 * 重载
	 */
	public void reload() {
		funcMap.clear();
		controllerClassMap.clear();
		init();
	}

	/**
	 * Manager方法执行拦截
	 * 
	 * @return false:拦截,true:不拦截
	 * @throws Throwable
	 */
	public boolean invoke(String funcKey) throws Exception {
		Assert.notNull(funcKey);
		if (funcMap.containsKey(funcKey)) {
			return funcMap.get(funcKey);
		}
		//return true;
		return false;
	}
	
	/**
	 * Controller执行拦截
	 * 
	 * @return
	 * @throws Throwable
	 */
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		if (controllerClassMap.containsKey(handler.getClass().getName())) {
			String funcKey = controllerClassMap.get(handler.getClass().getName());
			if (!invoke(funcKey)) {
				handleForbidden(funcKey, response);
			}
		}
		
//		VerFuncAnnotation vfa = handler.getClass().getAnnotation(VerFuncAnnotation.class);  		
//		if(vfa!=null&&!vfa.value()){
//			System.out.println("99999999999999"+vfa.value());
//			handleForbidden(handler.getClass().toString(), response);
//		}
		return true;
	}
	/**
	 * Controller 执行Action拦截
	 * @throws IOException
	 */
	public void controllerActionHandle(String funcKey, HttpServletResponse response){
		
		
		try {
			if (!invoke(funcKey)) {
				handleForbidden(funcKey, response);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}	
	}	

	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

	}

	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

	}

	/**
	 * 处理禁止的功能
	 * 
	 * @throws IOException
	 */
	public void handleForbidden(String funcKey, HttpServletResponse response) throws IOException {
		logger.error("current version do not support function:" + funcKey);
		response.sendError(403);
	}

	public class Constants {
		//开启
		public final static String ON = "on";
		//关闭
		public final static String OFF = "off";
		//分隔符
		public final static String SPLITER = "-";
		
		@FuncName(title="商品管理(多规格、关联规格、规格管理)")
		public final static String multiSku = "multiSku";
		@FuncName(title="缺货登记(缺货登记管理)")
		public final static String stockNotify = "stockNotify";
		@FuncName(title="专场目录(专场活动添加、修改、删除、设置过滤条件和手动添加商品)")
		public final static String virtualCategory = "virtualCategory";
		@FuncName(title="文章管理(文章关联推荐)")
		public final static String contentRelated4Content = "contentRelated4Content";
		@FuncName(title="内容目录管理(内容目录关联推荐)")
		public final static String contentRelated4Category = "contentRelated4Category";
		@FuncName(title="订单管理(代客下单/侵入service层)")
		public final static String placeOrderByAdmin = "placeOrderByAdmin";
		@FuncName(title="促销活动(购物车、目录、优惠券促销)")
		public final static String promoRule = "promoRule";
		@FuncName(title="礼券管理(礼券添加，禁用，发送礼券邮件)")
		public final static String giftCertificate = "giftCertificate";
		@FuncName(title="商品评论管理(查看客户评论/商品评论显示、隐藏、置顶、取消置顶、标识为已阅、标识为未阅、删除/管理员回复、查看回复)")
		public final static String productReview = "productReview";
		@FuncName(title="商品咨询管理(查看客户咨询/商品咨询显示、隐藏、标识为已阅、标识为未阅、删除/管理员回复、查看回复)")
		public final static String productConsult = "productConsult";
		@FuncName(title="客户注册项(添加、修改、删除自定义客户注册项)")
		public final static String customerAttr = "customerAttr";
		@FuncName(title="会员等级管理(添加修改删除客户等级、会员自动升级)")
		public final static String membership = "membership";
		@FuncName(title="会员自动升级(侵入service层)")
		public final static String membershipAutoUpgrade = "membershipAutoUpgrade";
		@FuncName(title="信息订阅(添加、修改、删除订阅信息分类/添加、修改、删除订阅信息/查看、删除订阅邮件)")
		public final static String subscriber = "subscriber";
		@FuncName(title="物流与配送(添加、修改、删除提货中心)")
		public final static String selfCollection = "selfCollection";
		@FuncName(title="税管理(添加、修改、删除税和税率)")
		public final static String tax = "tax";
		@FuncName(title="包装管理(添加、修改、删除包装)")
		public final static String wrap = "wrap";
		@FuncName(title="安全日志(查看、删除安全日志)")
		public final static String appAudit = "appAudit";
		@FuncName(title="导入(商品、商品目录、客户批量导入)")
		public final static String importTool = "importTool";
		@FuncName(title="系统环境信息(侵入jsp)")
		public final static String systemInfo = "systemInfo";
		@FuncName(title="标签管理(对商品、文章、订单、会员加入自定义标签)")
		public final static String tag = "tag";
		@FuncName(title="报表统计(销售额统计、订单交易量趋势、商品销售排行、会员购买排行、销售指标分析、会员注册量趋势)")
		public final static String report = "report";
		@FuncName(title="自定义区域(侵入service层)")
		public final static String regionDIY = "regionDIY";
		/**
		 * TODO 以下功能或功能项需要侵入前台jsp页面
		 */
		@FuncName(title="发票功能")
		public final static String invoice = "invoice";
		@FuncName(title="积分,积分支付")
		public final static String shopPoint = "shopPoint";
		@FuncName(title="匿名购物")
		public final static String checkoutAnonymity = "checkoutAnonymity";
		@FuncName(title="商品对比，对比栏")
		public final static String compareCart = "compareCart";
		/**
		 * TODO 以下功能或功能项未开发
		 */
		//模板管理(模板源码在线编辑及其他外围功能)
		//导出(商品、商品目录、客户批量导出)
		//短信队列
		//Discuz论坛整合
		//全文检索配置整合
		//礼品管理(添加修改删除礼品、排序礼品目录、促销活动赠送礼品)
		//public final static String gift = "gift";
		//限时抢购、秒杀
		//团购
		//捆绑商品
		//邮件模板编辑功能
		//站内信息模板编辑功能
		//手机短信模板编辑功能
		//消息发送配置
		//统计模块
		/**
		 * TODO 以下功能或功能项不需要
		 */

		//区域管理
		//public final static String region = "region";
	}
	
	public static String getVerFuncTitle(String funcKey){
		String funcKeyDecode = new String(Base64.decodeBase64(funcKey.getBytes()));
		Field field = null;
		try {
			field = VerFuncInterceptor.Constants.class.getDeclaredField(funcKeyDecode);
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
			return "未指明";
		}
		boolean otherFlag = field.isAnnotationPresent(FuncName.class);
		return otherFlag?field.getAnnotation(FuncName.class).title():"";
	}
	
	public static String getVerFuncKey(String funcKey){
		return new String(Base64.decodeBase64(funcKey.getBytes()));
	}
	
	public static String getVerFuncValue(String funcValue){
		String funcValueDecode = new String(Base64.decodeBase64(funcValue.getBytes()));
		String[] values = funcValueDecode.split(Constants.SPLITER);
		String onOrOff = values[1];
		return onOrOff;
	}
	
	public static String encodeVerFuncValue(String funcKey,String funcValue){
		return new String(Base64.encodeBase64((new String(Base64.decodeBase64(funcKey.getBytes()))+Constants.SPLITER+funcValue).getBytes()));
	}
	
	public static String encodeVerFuncKey(String funcKey){
		return new String(Base64.encodeBase64(funcKey.getBytes()));
	}

	public static void main(String[] args) {
//		Class cla = VerFuncInterceptor.Constants.class;
//		//解析属性信息
//		Field[] fieldArray = cla.getDeclaredFields();
//		StringBuffer sqlOff=new StringBuffer("truncate TABLE `ver_func`;");
//		StringBuffer sqlOn=new StringBuffer("truncate TABLE `ver_func`;");
//		
//		for (int i=0;i<fieldArray.length;i++) {
//			Field field =(Field)fieldArray[i];
//			if (!"this$0".equals(field.getName())) {
//				try {
//					//boolean otherFlag = field.isAnnotationPresent(FuncName.class);
//					//System.out.println("常量:" + field.getName() + "=" + field.get(cla)+"="+(otherFlag?field.getAnnotation(FuncName.class).title():""));
//					byte[] funcKeyBytes = ((String) field.get(cla)).getBytes();
//					String encodeFuncKey = new String(Base64.encodeBase64(funcKeyBytes));
//					System.out.println("funcKey加密值：" + encodeFuncKey);
//					byte[] funcValueOnBytes = ((String) field.get(cla) + Constants.SPLITER + Constants.ON).getBytes();
//					System.out.println("funcValue开放加密值：" + new String(Base64.encodeBase64(funcValueOnBytes)));
//					byte[] funcValueOffBytes = ((String) field.get(cla) + Constants.SPLITER + Constants.OFF).getBytes();
//					System.out.println("funcValue关闭加密值：" + new String(Base64.encodeBase64(funcValueOffBytes)));
//					System.out.println("funcKey解密值：" + new String(Base64.decodeBase64(encodeFuncKey.getBytes())));
//					System.out.println("-------------------------");
//					String endLine=";";
//					sqlOff.append("\nINSERT INTO `ver_func` (`funcKey`,`funcValue`) VALUES ('"+encodeFuncKey+"','"+new String(Base64.encodeBase64(funcValueOffBytes))+"')"+endLine);
//					sqlOn.append("\nINSERT INTO `ver_func` (`funcKey`,`funcValue`) VALUES ('"+encodeFuncKey+"','"+new String(Base64.encodeBase64(funcValueOnBytes))+"')"+endLine);
//				} catch (IllegalArgumentException e) {
//					e.printStackTrace();
//				} catch (IllegalAccessException e) {
//					e.printStackTrace();
//				}
//			}
//		}
//		//生成sql文件		
//		File vSqlOff = new File("E:\\verfun-off.sql");
//		File vSqlon = new File("E:\\verfun-on.sql");
//		 try {
//			BufferedWriter bwOff = new BufferedWriter(new FileWriter(vSqlOff));
//			BufferedWriter bwOn = new BufferedWriter(new FileWriter(vSqlon));
//			bwOff.write(sqlOff.toString());
//			bwOn.write(sqlOn.toString());
//			bwOff.close();
//			bwOn.close();
//			System.out.println("\n==============================");
//			System.out.println("\n生成sql文件：");
//			System.out.println("\n关闭功能:"+vSqlOff.getAbsolutePath());
//			System.out.println("\n开启功能:"+vSqlon.getAbsolutePath());
//			System.out.println("\n==============================");
//		} catch (IOException e) {
//			e.printStackTrace();
//		}
//
//		hehe.test.com/article.html?id=100 ==>www.test.com/hehe/article.html?id=100
		String url="http://hehe.test.com:8080/aaa/article.html";
		
		//Pattern pattern = Pattern.compile("://(.*?).test.com/.*?(.html|.jsp)");
		Pattern pattern = Pattern.compile("(\\w+:\\/\\/)?([^\\.]+)(\\.[^/:]+)(:\\d*)?([^# ]*)");
		Matcher matcher = pattern.matcher(url);
		String domain = matcher.find()?matcher.group(5):"www";
		if(!domain.equalsIgnoreCase("www")){
			//此时domain为需要的值，可设置在session中被controller层程序使用
			System.out.println(domain);
		}
		
		System.out.println("80.".split("\\.").length);
	}

	
}
